// Fixture for reading Analog input and write Analog waveforms

#include "../job.h"
#include<cmath>
#include <iostream>  // for debugging

struct InputOptionFixture
{
	InputOptionFixture() : temp(22), opt()
	{
	//	cout << "entering Option Fixture" << endl;
		// these strings came from TestThroughPackage.nb don'tforget trailing semicolon
		string sLong ="numchannels 1;samples 50;terminalmode 3;units 0;"
							"messagelevel 0;activeedge 0;setuponly 0;"
							"samplemode 0;transfermech 0;";
		string sDouble= "frequency 1000.0;min -10.0;max 10.0;timeout 10.0;";
		string sString = "channels dev1/ai0;clock OnboardClock;";

		opt.L = MyMap<long>(sLong);
		opt.D = MyMap<double>(sDouble);
		opt.S = MyMap<string>(sString);
		opt.getNIDAQConstants();
	}
	~InputOptionFixture() { /* cout << "any teardown needed?" << endl;*/}

	int temp;
	option opt;
};

struct OutputFixture
{
	OutputFixture() :  opt()
	{
	//	cout << "entering Option Fixture" << endl;
		// these strings came from TestThroughPackage.nb don'tforget trailing semicolon
		string sLong ="numchannels 1;samples 1;terminalmode 3;units 0;"
							"messagelevel 0;activeedge 0;setuponly 0;"
							"samplemode 0;transfermech 1;";
		string sDouble= "frequency 100.0;min -10.0;max 10.0;timeout 10.0;numperiods 1.0";
		string sString = "channels dev1/ao0;clock OnboardClock;";
		double tempWaveformData[] = {1.1};

		opt.L = MyMap<long>(sLong);
		opt.D = MyMap<double>(sDouble);
		opt.S = MyMap<string>(sString);
		opt.createarray("waveform", 2);  // size two for the moment
		opt.DArray["waveform"][0] = tempWaveformData[0];
		opt.getNIDAQConstants();
	}
	~OutputFixture() { /* cout << "any teardown needed?" << endl;*/}

	option opt;
};

struct IOFixture
{
	IOFixture() : In(), Out(), zeroVolts(0.00), pInputJob(0), pSineData(0), numPts(100)
	{
		pSineData = new double[numPts*sizeof(double)];
		for(int i =0;  i <numPts; i++)
			pSineData[i] = sin(2.0*3.1415*i/numPts);
	}
	~IOFixture()
	{
//		std::cout << "IOFixture DTor, pInputJob = "<<(long) pInputJob << std::endl;
		delete pInputJob;
		delete[] pSineData;
	}

	// shoud this be in main program ??
	void WriteImmediate()
	{
		OutputJob* jobptr = CreateOutputJob(persistJobs, Out.opt);
		OutputWaveformDispatch(jobptr, persistJobs, Out.opt);
	}
	InputJob* ReadImmediate(string taskName)
	{
		pInputJob = new InputJob(taskName, persistJobs, In.opt);
		pInputJob->readData();
		return pInputJob;
	}

	OutputJob* ContinuousSineWave(double magnitude = 1.00, double frequency = 1000.0)
	{
        CHECK_EQUAL(100, numPts);
        Out.opt.L["samples"] = numPts;
        Out.opt.D["numperiods"] = 3.0;
        Out.opt.D["frequency"] = frequency;
        Out.opt.L["samplemode"] = DAQmx_Val_ContSamps;
        Out.opt.createarray("waveform", numPts);
        for(int i = 0; i < numPts; i++)
            Out.opt.DArray["waveform"][i] = magnitude * pSineData[i];
    //	cout << Out.opt.toString() << endl;
        TaskHandle th = 0;			// task handle for persistent job
        OutputJob* outjobptr = CreateOutputJob(persistJobs, Out.opt);   // const references ?
        th = outjobptr->getTaskHandle(); CHECK(th !=0);
        outjobptr->startTask(th);
        return outjobptr;
	}

    OutputJob* ContinuousSquareWave(double magnitude = 5.00)
	{
        numPts = 20;
        Out.opt.L["samples"] = numPts;
        Out.opt.D["numperiods"] = 30.0; // any effect if DAQmx_Val_ContSamps used?
        Out.opt.L["samplemode"] = DAQmx_Val_ContSamps;
        Out.opt.createarray("waveform", numPts);
        Out.opt.D["frequency"] = 1000.0;
        Out.opt.createarray("waveform", numPts);
        for(int i = 0; i < numPts/2; i++)
            Out.opt.DArray["waveform"][i] = 0.0;
        for(int i = numPts/2 + 1; i < numPts; i++)
            Out.opt.DArray["waveform"][i] = magnitude;
    //	cout << Out.opt.toString() << endl;
        TaskHandle th = 0;			// task handle for persistent job
        OutputJob* outjobptr = CreateOutputJob(persistJobs, Out.opt);   // const references ?
        th = outjobptr->getTaskHandle(); CHECK(th !=0);
        outjobptr->startTask(th);
        return outjobptr;
	}

	InputOptionFixture In;
	OutputFixture Out;
	persistJobHolder persistJobs;
	double zeroVolts;
	InputJob* pInputJob;
	double* pSineData;
	int numPts;
};
